
#include "Utility.h"
#include <time.h>
#include <iostream>
#include "Randomiser.h"

namespace Util
{

MTRand_open Rand;

void SeedRandom()
{
	Rand.seed(time(0));
	//std::srand(time(0));
}

float Random(float min, float max)
{
	float frac = Rand();
	return (frac * (max-min)) + min;
	//return float(std::rand() % int(max-min) + min);
}

sf::Vector2f VecRand(float min, float max)
{
	return sf::Vector2f(Random(min,max), Random(min,max));
}

float Random(int min, int max)
{
	return int(Random(float(min), float(max)));
}

float Angle(sf::Vector2<float> Pos1, sf::Vector2<float> Pos2)
{
	float deg = RadToDeg(atan2( Pos1.y - Pos2.y, Pos1.x - Pos2.x ));
	return deg;
}

float RadToDeg(float Rad)
{
	return (180.f / M_PI) * Rad;
}

float DegToRad(float Deg)
{
	return (M_PI / 180.f) * Deg;
}

float NormalizeAngle(float Deg)
{
	return Deg - (360 * (std::floor((Deg + 180)/360)));
}

float Approach(float Current, float Target, float Inc)
{
	Inc = abs(Inc);

	if (Current < Target)
	{
		return std::min(Target, Current + Inc);
	}
	if (Current > Target)
	{
		return std::max(Target, Current - Inc);
	}
	return Current;
}

float Distance(sf::Vector2f One, sf::Vector2f Two)
{
	if (One == Two)
		return 0;
	return Length(One - Two);
}

float Length(sf::Vector2f Vec)
{
	return std::sqrt(std::pow(Vec.x,2) + std::pow(Vec.y, 2));
}

float LengthSquared(sf::Vector2f Vec)
{
	return std::pow(Vec.x,2) + std::pow(Vec.y, 2);
}

sf::Vector2f Normalize(sf::Vector2f Vec)
{
	float len = Length(Vec);
	Vec.x /= len;
	Vec.y /= len;
	return Vec;
}

float VecDot(sf::Vector2f One, sf::Vector2f Two)
{
	return (One.x * Two.x) + (One.y * Two.y);
}

float VecCross(sf::Vector2f One, sf::Vector2f Two)
{
	return (One.x * Two.y) + (One.y * Two.x);
}

sf::Vector2f VecProject(sf::Vector2f Point, sf::Vector2f Axis)
{
	float dp = VecDot(Point,Axis);
	float Len = LengthSquared(Axis);
	sf::Vector2f Proj;
	Proj.x = ( dp / Len ) * Axis.x;
	Proj.y = ( dp / Len ) * Axis.y;
	return Proj;
}


float PointToLineDist(sf::Vector2f One, sf::Vector2f Two, sf::Vector2f Point)
{
	// Return minimum distance between line segment vw and point p
	const float l2 = LengthSquared(One - Two);
	if (l2 == 0.0) return Distance(Point, One);

	const float t = VecDot(Point - One, Two - One) / l2;
	if (t < 0.0) return Distance(Point, One);       // Beyond the 'v' end of the segment
	else if (t > 1.0) return Distance(Point, Two);  // Beyond the 'w' end of the segment
	const sf::Vector2f projection = One + t * (Two - One);  // Projection falls on the segment
	return LengthSquared(Point-projection);
}

float RotateTowards(float ang , float targ, float speed)
{
	if (ang == targ)
		return ang;
	//if (abs(((((argument0-argument1) mod 360)+540) mod 360)-180) >= 179) {
		//return argument0+1;
		
	return ang+(std::sin(DegToRad(targ-ang))*speed);
}

sf::Vector2f VecNormal(sf::Vector2f Vec)
{
	sf::Vector2f n;
	float len = Length(Vec);
	if (len == 0)
		return sf::Vector2f(0,0);
	n.x = (Vec.y * -1) / len;
	n.y = Vec.x / len;

	return n;
}

sf::Vector2f VecScale(sf::Vector2f Vec, float scale)
{
	Vec.x *= scale;
	Vec.y *= scale;
	return Vec;
}

}